<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="author" content="https://gitee.com/fldx/ruler" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="keywords" content="屏幕尺子,在线尺子,开源屏幕尺子,全屏尺子" />
    <title>在线屏幕尺子</title>
    <style>
      * {
        box-sizing: border-box;
      }
      html,
      body {
        margin: 0;
        padding: 0;
        overflow: hidden;
        background-color: #fff;
      }
      .ruler-dpi {
        width: 1in;
        height: 1in;
        position: fixed;
        top: 0;
        left: -1in;
      }
      .ruler-canvas {
        width: 100vw;
        height: 100vh;
        display: block;
      }
      .full-screen {
        position: fixed;
        right: 10px;
        bottom: 10px;
        
      }
    </style>
  </head>
  <body>
    <div class="ruler-dpi"></div>
    <canvas class="ruler-canvas"></canvas>
    <div class="full-screen">
      <div>屏幕DPI: <span class="dpi"></span></div>
      <div title="误差范围约一个像素">误差范围: ±<span class="error"></span>mm</div>
      <button id="full-screen">开启全屏</button>
    </div>
    <script>
      /**
       * 选项
       * @typedef Option
       * @property {number} DPI 一英寸有多少像素
       */
      /**
       * 尺子
       * @param {HTMLCanvasElement|String} canvas 容器
       * @param {Option} options 选项
       * @constructor
       */
      function Ruler(canvas, options) {
        /**
         * @type {HTMLCanvasElement}
         */
        this.canvas = null;
        if (typeof canvas === "string") {
          this.canvas = document.querySelector(canvas);
        } else if (canvas instanceof HTMLCanvasElement) {
          this.canvas = canvas;
        }
        if (this.canvas == null) throw "画布不能为空";
        /**
         * 画布上下文
         * @type {CanvasRenderingContext2D}
         */
        this.context = this.canvas.getContext("2d");
        this.cmSize = options.DPI / 2.54;
        this.mmSize = options.DPI / 25.4;
        this.canvas.width = this.canvas.clientWidth;
        this.canvas.height = this.canvas.clientHeight;
        this.context.font = "16px Arial";
        this.update();
        var me = this;
        window.addEventListener("resize", function () {
          //console.log(this);
          me.canvas.width = me.canvas.clientWidth;
          me.canvas.height = me.canvas.clientHeight;
          me.context.font = "16px Arial";
          me.update();
        });
      }

      Ruler.prototype.update = function () {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.drawGraduations();
      };

      /**
       * 计算
       * @param {number} mm 毫米
       */
      Ruler.prototype.compute = function (mm) {
        var px = Math.floor(this.mmSize * mm);
        var len = 2;
        var cm = Math.floor(mm / 10).toString();
        if (mm % 5 === 0) len = 3;
        if (mm % 10 === 0) len = 5;
        return { len: len * this.mmSize, px: px + 0.5 };
      };

      /**
       * 画横轴刻度
       * @param {number} mm 毫米
       */
      Ruler.prototype.drawHorizontal = function (mm) {
        var d = this.compute(mm);
        var px = d.px, len = d.len;
        this.context.moveTo(px, 0);
        this.context.lineTo(px, len);

        if (mm > 0 && mm % 10 === 0) {
          var cm = Math.floor(mm / 10).toString();
          var mText = this.context.measureText(cm);
          this.context.strokeText(cm, px - mText.width / 2, len + 16);
        }
      };
      /**
       * 画竖轴刻度
       * @param {number} mm 毫米
       */
      Ruler.prototype.drawVertical = function (mm) {
        var d = this.compute(mm);
        var px = d.px, len = d.len;
        this.context.moveTo(0, px);
        this.context.lineTo(len, px);

        if (mm > 0 && mm % 10 === 0) {
          var cm = Math.floor(mm / 10).toString();
          var mText = this.context.measureText(cm);
          this.context.strokeText(cm, len + 4, px + 4);
        }
      };

      Ruler.prototype.drawGraduations = function () {
        var mmWidth = Math.ceil(this.canvas.width / this.mmSize);
        this.context.strokeStyle = "#ff0000";
        for (var i = 1; i < mmWidth; i++) {
          this.drawHorizontal(i);
        }

        var mmHeight = Math.ceil(this.canvas.height / this.mmSize);
        for (var i = 1; i < mmHeight; i++) {
          this.drawVertical(i);
        }
        this.context.stroke();
      };
    </script>
    <script>
      var base = document.querySelector(".ruler-dpi");
      var dpi=base.clientWidth;
      new Ruler(".ruler-canvas", { DPI:  dpi});
      
      function launchFullScreen(element) {
        if (element.requestFullscreen) {
          element.requestFullscreen();
        } else if (element.mozRequestFullScreen) {
          element.mozRequestFullScreen();
        } else if (element.webkitRequestFullscreen) {
          element.webkitRequestFullscreen();
        } else if (element.msRequestFullscreen) {
          element.msRequestFullscreen();
        }
      }
      function exitFullscreen() {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        }
      }
      var fs = document.querySelector('.full-screen');
      fs.querySelector('.dpi').innerText=dpi;
      fs.querySelector('.error').innerText=(25.4/2/dpi).toFixed(2);
      var btn=fs.querySelector('#full-screen');
      btn.addEventListener("click", function () {
        var isFullScreen =
          document.fullscreenElement ||
          document.mozFullScreenElement ||
          document.webkitFullscreenElement;
        if (isFullScreen) {
          exitFullscreen(document.body);
          btn.innerText = "开启全屏";
        } else {
          launchFullScreen(document.body);
          btn.innerText = "退出全屏";
        }
      });
      fs.style.opacity=1;
      setInterval(function () {
        var o = parseFloat(fs.style.opacity);
        if (o > 0) fs.style.opacity = o - 0.02;
      }, 100);

      fs.addEventListener("mousemove", function () {
        this.style.opacity = 1;
      });
      window.addEventListener('resize',function(){
        fs.style.opacity=1;
      })
    </script>
  </body>
</html>
